package com.sz.virtualbank.service.transaction.impl;

import com.sz.virtualbank.common.exception.BusinessException;
import com.sz.virtualbank.common.utils.CheckUtil;
import com.sz.virtualbank.dao.entity.TradeRecord;
import com.sz.virtualbank.dao.entity.User;
import com.sz.virtualbank.dao.mapper.TradeRecordMapper;
import com.sz.virtualbank.dao.mapper.UserMapper;
import com.sz.virtualbank.service.transaction.TransactionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;

/**
 * 交易服务实现类
 * 
 * @author Claude
 */
@Slf4j
@Service
public class TransactionServiceImpl implements TransactionService {

    @Autowired
    private TradeRecordMapper tradeRecordMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    /**
     * 交易类型：充值
     */
    private static final int TRADE_TYPE_RECHARGE = 1;
    
    /**
     * 交易类型：提现
     */
    private static final int TRADE_TYPE_WITHDRAW = 2;
    
    /**
     * 交易类型：转账
     */
    private static final int TRADE_TYPE_TRANSFER = 3;
    
    /**
     * 交易状态：处理中
     */
    private static final int TRADE_STATUS_PROCESSING = 0;
    
    /**
     * 交易状态：成功
     */
    private static final int TRADE_STATUS_SUCCESS = 1;
    
    /**
     * 交易状态：失败
     */
    private static final int TRADE_STATUS_FAILED = 2;
    
    /**
     * 内部交易渠道
     */
    private static final String CHANNEL_INTERNAL = "INTERNAL";
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TradeRecord createTradeRecord(Long userId, Integer tradeType, BigDecimal amount, 
                                       String targetAccount, String remark, String channel) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(tradeType, "交易类型不能为空")
                .notNull(amount, "交易金额不能为空");
        
        // 查询用户
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 创建交易记录
        TradeRecord tradeRecord = new TradeRecord();
        tradeRecord.setTradeNo(generateTradeNo(tradeType));
        tradeRecord.setUserId(userId);
        tradeRecord.setTradeType(tradeType);
        tradeRecord.setAmount(amount);
        tradeRecord.setBalance(user.getBalance()); // 初始余额
        tradeRecord.setTargetAccount(targetAccount);
        tradeRecord.setStatus(TRADE_STATUS_PROCESSING);
        tradeRecord.setRemark(remark);
        tradeRecord.setCreateTime(LocalDateTime.now());
        tradeRecord.setUpdateTime(LocalDateTime.now());
        tradeRecord.setChannel(StringUtils.isNotBlank(channel) ? channel : CHANNEL_INTERNAL);
        
        tradeRecordMapper.insert(tradeRecord);
        
        return tradeRecord;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TradeRecord recharge(Long userId, BigDecimal amount, String channel) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(amount, "充值金额不能为空")
                .isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "充值金额必须大于0");
        
        // 查询用户
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 创建交易记录
        TradeRecord tradeRecord = createTradeRecord(userId, TRADE_TYPE_RECHARGE, amount, null, "账户充值", channel);
        
        // 更新账户余额
        int rows = userMapper.updateBalance(userId, amount);
        if (rows <= 0) {
            throw BusinessException.of(5000, "充值失败，请稍后再试");
        }
        
        // 更新交易状态和余额
        User updatedUser = userMapper.selectById(userId);
        tradeRecord.setBalance(updatedUser.getBalance());
        tradeRecord.setStatus(TRADE_STATUS_SUCCESS);
        tradeRecord.setUpdateTime(LocalDateTime.now());
        tradeRecordMapper.updateStatusById(tradeRecord.getId(), TRADE_STATUS_SUCCESS);
        
        return tradeRecord;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TradeRecord withdraw(Long userId, BigDecimal amount, String channel) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(amount, "提现金额不能为空")
                .isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "提现金额必须大于0");
        
        // 查询用户
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 检查余额是否充足
        CheckUtil.Biz.INSTANCE.isTrue(user.getBalance().compareTo(amount) >= 0, "账户余额不足");
        
        // 创建交易记录
        TradeRecord tradeRecord = createTradeRecord(userId, TRADE_TYPE_WITHDRAW, amount.negate(), null, "账户提现", channel);
        
        // 更新账户余额
        int rows = userMapper.updateBalance(userId, amount.negate());
        if (rows <= 0) {
            throw BusinessException.of(5000, "提现失败，请稍后再试");
        }
        
        // 更新交易状态和余额
        User updatedUser = userMapper.selectById(userId);
        tradeRecord.setBalance(updatedUser.getBalance());
        tradeRecord.setStatus(TRADE_STATUS_SUCCESS);
        tradeRecord.setUpdateTime(LocalDateTime.now());
        tradeRecordMapper.updateStatusById(tradeRecord.getId(), TRADE_STATUS_SUCCESS);
        
        return tradeRecord;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TradeRecord transfer(Long userId, String targetAccount, BigDecimal amount, String remark) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notEmpty(targetAccount, "转账目标账户不能为空")
                .notNull(amount, "转账金额不能为空")
                .isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "转账金额必须大于0");
        
        // 查询转出用户
        User fromUser = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(fromUser, "用户不存在");
        
        // 查询转入用户
        User toUser = userMapper.selectByUsername(targetAccount);
        if (toUser == null) {
            toUser = userMapper.selectByPhone(targetAccount);
        }
        CheckUtil.Biz.INSTANCE.notNull(toUser, "转账目标账户不存在");
        
        // 不能给自己转账
        CheckUtil.Biz.INSTANCE.isTrue(!fromUser.getId().equals(toUser.getId()), "不能给自己转账");
        
        // 检查余额是否充足
        CheckUtil.Biz.INSTANCE.isTrue(fromUser.getBalance().compareTo(amount) >= 0, "账户余额不足");
        
        // 创建转出交易记录
        TradeRecord fromRecord = createTradeRecord(userId, TRADE_TYPE_TRANSFER, amount.negate(), 
                                                 targetAccount, StringUtils.isNotBlank(remark) ? remark : "转账支出", 
                                                 CHANNEL_INTERNAL);
        
        // 创建转入交易记录
        TradeRecord toRecord = createTradeRecord(toUser.getId(), TRADE_TYPE_TRANSFER, amount, 
                                               fromUser.getUsername(), StringUtils.isNotBlank(remark) ? remark : "转账收入", 
                                               CHANNEL_INTERNAL);
        
        // 更新转出账户余额
        int fromRows = userMapper.updateBalance(userId, amount.negate());
        if (fromRows <= 0) {
            throw BusinessException.of(5000, "转账失败，请稍后再试");
        }
        
        // 更新转入账户余额
        int toRows = userMapper.updateBalance(toUser.getId(), amount);
        if (toRows <= 0) {
            throw BusinessException.of(5000, "转账失败，请稍后再试");
        }
        
        // 更新转出交易状态和余额
        User updatedFromUser = userMapper.selectById(userId);
        fromRecord.setBalance(updatedFromUser.getBalance());
        fromRecord.setStatus(TRADE_STATUS_SUCCESS);
        fromRecord.setUpdateTime(LocalDateTime.now());
        tradeRecordMapper.updateStatusById(fromRecord.getId(), TRADE_STATUS_SUCCESS);
        
        // 更新转入交易状态和余额
        User updatedToUser = userMapper.selectById(toUser.getId());
        toRecord.setBalance(updatedToUser.getBalance());
        toRecord.setStatus(TRADE_STATUS_SUCCESS);
        toRecord.setUpdateTime(LocalDateTime.now());
        tradeRecordMapper.updateStatusById(toRecord.getId(), TRADE_STATUS_SUCCESS);
        
        return fromRecord;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateTradeStatus(String tradeNo, Integer status) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notEmpty(tradeNo, "交易流水号不能为空")
                .notNull(status, "交易状态不能为空");
        
        // 查询交易记录
        TradeRecord tradeRecord = tradeRecordMapper.selectByTradeNo(tradeNo);
        CheckUtil.Biz.INSTANCE.notNull(tradeRecord, "交易记录不存在");
        
        // 只能更新处理中的交易
        if (!(TRADE_STATUS_PROCESSING == tradeRecord.getStatus())) {
            return false;
        }
        
        // 更新交易状态
        tradeRecord.setStatus(status);
        tradeRecord.setUpdateTime(LocalDateTime.now());
        return tradeRecordMapper.updateStatusById(tradeRecord.getId(), status) > 0;
    }
    
    @Override
    public List<TradeRecord> listTradeRecords(Long userId, int pageNum, int pageSize) {
        // 参数校验
        CheckUtil.Biz.INSTANCE.notNull(userId, "用户ID不能为空");
        
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 分页参数处理
        if (pageNum <= 0) {
            pageNum = 1;
        }
        if (pageSize <= 0) {
            pageSize = 10;
        }
        
        // 计算偏移量
        int offset = (pageNum - 1) * pageSize;
        
        // 查询交易记录
        return tradeRecordMapper.selectByUserId(userId, offset, pageSize);
    }
    
    @Override
    public List<TradeRecord> listTradeRecordsByType(Long userId, Integer tradeType, int pageNum, int pageSize) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(tradeType, "交易类型不能为空");
        
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 分页参数处理
        if (pageNum <= 0) {
            pageNum = 1;
        }
        if (pageSize <= 0) {
            pageSize = 10;
        }
        
        // 计算偏移量
        int offset = (pageNum - 1) * pageSize;
        
        // 查询交易记录
        return tradeRecordMapper.selectByUserIdAndType(userId, tradeType, offset, pageSize);
    }
    
    @Override
    public List<TradeRecord> listTradeRecordsByDateRange(Long userId, LocalDateTime startTime, 
                                                      LocalDateTime endTime, int pageNum, int pageSize) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(startTime, "开始时间不能为空")
                .notNull(endTime, "结束时间不能为空");
        
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 分页参数处理
        if (pageNum <= 0) {
            pageNum = 1;
        }
        if (pageSize <= 0) {
            pageSize = 10;
        }
        
        // 计算偏移量
        int offset = (pageNum - 1) * pageSize;
        
        // 查询交易记录
        return tradeRecordMapper.selectByUserIdAndDateRange(userId, startTime, endTime, offset, pageSize);
    }
    
    @Override
    public int countTradeRecords(Long userId) {
        // 参数校验
        CheckUtil.Biz.INSTANCE.notNull(userId, "用户ID不能为空");
        
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 查询交易记录总数
        return tradeRecordMapper.selectCountByUserId(userId);
    }
    
    @Override
    public int countTradeRecordsByType(Long userId, Integer tradeType) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(tradeType, "交易类型不能为空");
        
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 查询交易记录总数
        return tradeRecordMapper.selectCountByUserIdAndType(userId, tradeType);
    }
    
    @Override
    public int countTradeRecordsByDateRange(Long userId, LocalDateTime startTime, LocalDateTime endTime) {
        // 参数校验
        CheckUtil.Biz.INSTANCE
                .notNull(userId, "用户ID不能为空")
                .notNull(startTime, "开始时间不能为空")
                .notNull(endTime, "结束时间不能为空");
        
        // 检查用户是否存在
        User user = userMapper.selectById(userId);
        CheckUtil.Biz.INSTANCE.notNull(user, "用户不存在");
        
        // 查询交易记录总数
        return tradeRecordMapper.selectCountByUserIdAndDateRange(userId, startTime, endTime);
    }
    
    @Override
    public TradeRecord getTradeDetail(String tradeNo) {
        // 参数校验
        CheckUtil.Biz.INSTANCE.notEmpty(tradeNo, "交易流水号不能为空");
        
        // 查询交易记录
        TradeRecord tradeRecord = tradeRecordMapper.selectByTradeNo(tradeNo);
        CheckUtil.Biz.INSTANCE.notNull(tradeRecord, "交易记录不存在");
        
        return tradeRecord;
    }
    
    /**
     * 生成交易流水号
     * 
     * @param tradeType 交易类型
     * @return 交易流水号
     */
    private String generateTradeNo(Integer tradeType) {
        // 交易类型前缀
        String prefix = "";
        switch (tradeType) {
            case TRADE_TYPE_RECHARGE:
                prefix = "R";
                break;
            case TRADE_TYPE_WITHDRAW:
                prefix = "W";
                break;
            case TRADE_TYPE_TRANSFER:
                prefix = "T";
                break;
            default:
                prefix = "O";
                break;
        }
        
        // 年月日时分秒
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        
        // 随机6位数
        String random = String.format("%06d", (int) (Math.random() * 1000000));
        
        return prefix + date + random;
    }
}
